from django.shortcuts import render

# Create your views here.
from rest_framework.authentication import BasicAuthentication, SessionAuthentication
from rest_framework.filters import OrderingFilter
from rest_framework.generics import GenericAPIView, ListCreateAPIView, RetrieveUpdateDestroyAPIView
from rest_framework.mixins import *
from rest_framework.pagination import PageNumberPagination
from rest_framework.permissions import IsAuthenticated
from rest_framework.throttling import UserRateThrottle
from rest_framework.viewsets import ModelViewSet

from .models import HeroInfo
from .serializers import HeroInfoModelSerializer


"""
对bookmanagment/views.py中的类进行封装
"""

class HerosView(ListModelMixin, CreateModelMixin, GenericAPIView):
    # 指定查询语句
    queryset = HeroInfo.objects.filter(is_delete=False)
    # 指定序列化器类型
    serializer_class = HeroInfoModelSerializer

    def get(self, request):
        return self.list(request)

    def post(self, request):
        return self.create(request)


class HeroView(RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin, GenericAPIView):
    queryset = HeroInfo.objects.filter(is_delete=False)
    serializer_class = HeroInfoModelSerializer

    def get(self, request, pk):
        return self.retrieve(request, pk)

    def put(self, request, pk):
        return self.update(request, pk)

    def patch(self, request, pk):
        return self.update(request, pk, partial=True)

    def delete(self, request, pk):
        return self.destroy(request, pk)


"""
在考虑会将上述单数形式和复数形式的定义合并(即上述完整增删改查完全定义在一个类中)时,
由于同一个类中不允许有同名方法,因此会采取改名称的方式,而改了名称后要让dispatch识别,
那么需在as_view()方法中增加参数,如:
urlpatterns = [
    url(r'^books/$', BookInfoViewSet.as_view({'get':'list'}),
    url(r'^books/(?P<pk>\d+)/$', BookInfoViewSet.as_view({'get': 'retrieve'})
]
或者采取action属性的方式, 例子见readme.txt
(这里仍然需要在url中定义两个路由)
"""

"""
对上述代码进一步封装
"""

class HerosView2(ListCreateAPIView):
    queryset = HeroInfo.objects.filter(is_delete=False)
    serializer_class = HeroInfoModelSerializer


class HeroView2(RetrieveUpdateDestroyAPIView):

    """
    queryset一般等价调用以下方法(有特例不等价,比如查询当前登录用户的收货地址):
    def get_queryset(self):
        return HeroInfo.objects.filter(is_delete=False)
    而get_queryset()方法会在get()方法中list调用
    """
    queryset = HeroInfo.objects.filter(is_delete=False)
    """
    serializer_class一般等价调用以下方法(也有特例):
    def get_serializer_class(self):
        return HeroInfoModelSerializer
    """
    serializer_class = HeroInfoModelSerializer


"""
继续对上述代码进一步封装
"""

# 完整的增删改查
class HeroViewSet(ModelViewSet):
    queryset = HeroInfo.objects.filter(is_delete=False)
    serializer_class = HeroInfoModelSerializer
    # 过滤: 指定检索方式(字段),项目中使用另一种检索方式,需在配置文件中添加过滤后端INSTALLED_APPS设置'django_filters'以及REST_FRAMEWORK中'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',)
    # 如: 127.0.0.1:8000/books/?btitle=西游记
    filter_fields = ['hname']
    # 指定排序字段  如: 127.0.0.1:8000/books/?ordering=-bread
    # filter_backends指明使用OrderingFilter过滤器来按照ordering_fields指定字段对数据集进行排序
    filter_backends = [OrderingFilter]
    ordering_fields = ['id']
    # 给本视图添加基本认证和session认证, 认证失败可能有两种返回值401 Unauthorized 未认证///403 Permission Denied 权限被禁止
    authentication_classes = (SessionAuthentication, BasicAuthentication)
    # 权限管理设置
    """
    AllowAny 允许所有用户
    IsAuthenticated 仅通过认证的用户
    IsAdminUser 仅管理员用户
    IsAuthenticatedOrReadOnly 认证的用户可以完全操作，否则只能get读取
    也可自定义
    """
    permission_classes = (IsAuthenticated,)
    # 限流
    """
    AnonRateThrottle: 限制所有匿名未认证用户，使用IP区分用户,使用DEFAULT_THROTTLE_RATES['anon'] 来设置频次
    UserRateThrottle: 限制认证用户，使用User id 来区分,使用DEFAULT_THROTTLE_RATES['user'] 来设置频次
    ScopedRateThrottle: 限制用户对于每个视图的访问频次，使用ip或user id
    或设置具体限制如: throttle_scope = 'uploads'
    """
    throttle_classes = (UserRateThrottle,)
    # 设置分页  # 127.0.0.1/books/?page=1&page_size=2
    pagination_class = LargeResultsSetPagination  # 如需关闭分页功能则设置为None



class LargeResultsSetPagination(PageNumberPagination):
    page_size = 1000  # 每页数目
    page_size_query_param = 'page_size'  # 前端发送的每页数目关键字名，默认为None
    max_page_size = 10000  # 前端最多能设置的每页数量
    # page_query_param 前端发送的页数关键字名，默认为"page"
